package com.rrd.dw.mr.gzip.bhzxzd;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer.Context;

import com.rrd.dw.utils.DateUtil;

 

/**
 * 百行助贷D3存量数据处理
 * @author liubaoxin
 * 2019-10-13
 */
public class BHZXZDAdvancePayoffUtils {
	public static final String CRT_FLAG = "\001";
    public static final Pattern CRT_PATTERN = Pattern.compile(CRT_FLAG);
    private static NullWritable key_null = NullWritable.get();
	private static Text val_Text = new Text();
	private final static int K=10;
    /**
     * 对每一笔还款记录进行判断，选择对应处理逻辑
     * @param context
     * @param map
     * @throws InterruptedException 
     * @throws IOException 
     */
	public static void process(Context context,List<Map<String,String>> list_map) throws IOException, InterruptedException{
		String target_repayment_date="";
		String target_repayment_date_k="";  
		String payoff_date="";
		int term_no=0;
		String min_date=""; 
		String loan_payoff_time=null;
		List<String> list = new ArrayList<String>();
		String dt="2019-11-01";
		Map<String,List<String>> pay_map = new HashMap<String,List<String>>();
		for(Map<String,String> map:list_map){ 
			 
			try{
			 
			payoff_date=BHZXZDUtils.time_to_date(map.get("payoff_time")); 
			target_repayment_date=BHZXZDUtils.time_to_date(map.get("target_repayment_date"));
			target_repayment_date_k=DateUtil.formateDateStr(DateUtil.addDay(DateUtil.formateToDate(target_repayment_date,"yyyy-MM-dd"), K+1),"yyyy-MM-dd");
			
			loan_payoff_time=BHZXZDUtils.time_to_date(map.get("loan_payoff_time"));
			term_no=Integer.parseInt(map.get("term_no"));
			if((target_repayment_date.compareTo(dt)>0 && (payoff_date.equals("") 
					|| payoff_date.compareTo(dt)>0)) 
					){
				context.getCounter("state","not.due_date.records").increment(1);   //未到期的还款计划
				min_date="";
				process_normal_pass(context,list_map,map);
				continue;
			}
			//提前还款或正常还款的情况
			if(!payoff_date.equals("") && payoff_date.compareTo(target_repayment_date_k)<0){
				min_date="";
				context.getCounter("state","normal.records").increment(1);
//				 System.out.println("提前结清："+advance_payoff_time+","+payoff_date);
			   if(!loan_payoff_time.equals("") && loan_payoff_time.compareTo(payoff_date)<=0){
				   if(map.get("loan_status2").equals("ZZ")){
						process_chuzhi(context, list_map, map);
					}else{
						 process_advanceoff(context,list_map,map,min_date);
					}
				  
				   break;
			   }else{
				min_date=process_normal(context,list_map,map,min_date);
			   }
			}
			//判断是否首期垫付结清
			if(!loan_payoff_time.equals("") && ((loan_payoff_time.compareTo(target_repayment_date)<=0 && term_no==1) )){
				min_date="";
				process_advanceoff(context,list_map,map,min_date);
				break;
			} 
			
			//逾期未还、逾期已还的情况
			if(payoff_date.equals("") ||  payoff_date.compareTo(target_repayment_date_k)>=0){
				context.getCounter("state","overdue.records").increment(1);
				
				//逾期情况 
				if(min_date.equals("")){
					min_date=map.get("target_repayment_date");
				} 
				
				//应还款日+宽限期次日上报
				//判断如果在“应还款日+宽限期次日”有实际还款记录则不进行“应还款日+宽限期次日”上报
				if(!payoff_date.equals("") && (loan_payoff_time.equals("") || loan_payoff_time.compareTo(payoff_date)>0)){
					//同一天还款的记录起来，进行统一处理
					if(pay_map.containsKey(payoff_date)){
						pay_map.get(payoff_date).add(map.get("term_no"));
					}else{
						List<String> listaa= new ArrayList<String>();
						listaa.add(map.get("term_no"));
						pay_map.put(payoff_date, listaa);
					}
					list.add(map.get("payoff_time")+","+map.get("next_payoff_time")+","+map.get("planned_payment")+","+map.get("term_no"));
				} 
				//逾期未还的数据，如果在宽限期次日进行了还款则不报送逾期记录，合并还款日和宽限期次日同事发生的情况
				if(!isExists(target_repayment_date_k,list) && (loan_payoff_time.equals("") || loan_payoff_time.compareTo(target_repayment_date_k)>0)){
				   process_overdue_day(context,list_map,map,min_date);
					
				} 

			}
			//处理逾期还款记录的情况,发生在账期内则进行上报
			if(pay_map.size()>0){
				min_date=OverdueProcess.process_overdue_pay(context, list_map, map, pay_map,min_date);
			}
			
			//最后一期，且没有进行还款，则对该期进行 30 60 90 ...上报
			if( term_no==Integer.parseInt(map.get("last_period")) && (!map.get("loan_status").equals("3") && !map.get("loan_status").equals("5"))){
				if(min_date.equals("")){
					min_date=map.get("target_repayment_date");
				}
				OverdueProcess.process_last_period(context, list_map, map,  min_date,dt);
				if(!loan_payoff_time.equals("") &&  loan_payoff_time.compareTo(target_repayment_date)>0){
					 if(map.get("loan_status2").equals("ZZ")){
							process_chuzhi(context, list_map, map);
						}else{
							 process_advanceoff(context,list_map,map,min_date);
						}
					break;
				}
			} 
			}catch(Exception e){
				System.out.println("-------------------"+map.get("next_payoff_time"));
				context.getCounter("error","act_payoff.err").increment(1);
				throw e;
		}  
		}
	}
	private static boolean isExists(String target_repayment_date_k,List<String> list){
		boolean bool=false;
		for(String s:list){
			if(target_repayment_date_k.equals(BHZXZDUtils.time_to_date(s.split(",")[0]))){
				bool=true;
			}
		}
		return bool;
	}
	/**
	 * 处理正常还款、提前还款场景
	 * @param context
	 * @param list_maps
	 * @param act_payoff_time
	 * @param term_no
	 * @param act_term_no
	 * @throws IOException
	 * @throws InterruptedException
	 */
	private static String process_normal(Context context,List<Map<String,String>> list_maps,Map<String,String> map,String min_date) throws IOException, InterruptedException{
			String arr[]=null;
			int term_no = Integer.parseInt(map.get("term_no"));
			int old_days=0;
			String act_payoff_date=BHZXZDUtils.time_to_date(map.get("payoff_time"));
			arr = getLoan_due_amt(list_maps, term_no, term_no, act_payoff_date);
			map.put("target_repayment", arr[0]);
			map.put("remaining_amount", arr[1]);
			map.put("real_repayment", arr[2]);
			map.put("overdue_amount", arr[3]); //当 前 逾期总额 
		
			if(Double.parseDouble(arr[3])>0 && !min_date.equals("")){
				old_days=DateUtil.date_diff(BHZXZDUtils.time_to_date(map.get("payoff_time")), min_date);
			}else{
				old_days=0;
				min_date="";
			}
//			if(map.get("period_status").equals("ADVANCE_PAYOFF")){ //代偿
//				map.put("term_status",old_days<=30?"thirdPartyPayIn30":"compensation");
//			}else{
//				map.put("term_status",old_days>K?"overdue":"normal");
//			}
			map.put("term_status",old_days>K?"overdue":"normal");
			map.put("real_repayment_date",map.get("payoff_time")); //实际还款时间
			map.put("overdue_status",old_days>K?"D"+old_days:"");
			map.put("status_confirm_at",map.get("payoff_time"));
			if(term_no==Integer.parseInt(map.get("last_period")) && old_days<=0){
				map.put("loan_status", "3");
			}else if(old_days<=0) {
				map.put("loan_status", "1");
			}else{
				map.put("loan_status", "2");
			};
			map.put("period_list", arr[4]);	
			val_Text.set(BHZXZDUtils.processZhudaiToString(map));
			context.write(key_null, val_Text);
		return min_date;
	}
	private static void process_normal_pass (Context context,List<Map<String,String>> list_maps,Map<String,String> map) throws IOException, InterruptedException{
		int term_no = Integer.parseInt(map.get("term_no"));
		int old_days=0;
		double remain_amt = getLoan_remain_amt(list_maps);
		map.put("target_repayment", "0");
		map.put("target_repayment",map.get("planned_payment"));
		map.put("remaining_amount", String.valueOf(remain_amt));
		map.put("real_repayment", "0");
		map.put("overdue_amount", "0"); //当 前 逾期总额 
		map.put("term_status","UNProcess");
		map.put("real_repayment_date",map.get("payoff_time")); //实际还款时间
		map.put("overdue_status","");
		map.put("status_confirm_at","");
		if(term_no==Integer.parseInt(map.get("last_period")) && old_days<=0){
			map.put("loan_status", "3");
		}else if(old_days<=0) {
			map.put("loan_status", "1");
		}else{
			map.put("loan_status", "2");
		};
		val_Text.set(BHZXZDUtils.processZhudaiToString(map));
		context.write(key_null, val_Text);
	
}
	
	/**
	 * 处理逾期场景，逾期+宽限期次日上报
	 * @param context
	 * @param list_maps
	 * @param map
	 * @param min_date
	 * @throws IOException
	 * @throws InterruptedException
	 */
	private static double process_overdue_day(Context context,List<Map<String,String>> list_maps,Map<String,String> map,String min_date) throws IOException, InterruptedException{
		   String  arr[]=null;
			String target_repayment_date="";
			String target_repayment_date_k="";
			target_repayment_date=BHZXZDUtils.time_to_date(map.get("target_repayment_date"));
			target_repayment_date_k=DateUtil.formateDateStr(DateUtil.addDay(DateUtil.formateToDate(target_repayment_date,"yyyy-MM-dd"), K+1),"yyyy-MM-dd");
			//观察日
			String status_confirm_at=target_repayment_date_k; 
			int old_days=0;
			
			old_days=DateUtil.date_diff(status_confirm_at,min_date );
			arr = getLoan_due_amt(list_maps, Integer.parseInt(map.get("term_no")), 0, "no");
			map.put("target_repayment", arr[0]);
			map.put("remaining_amount", arr[1]);
			map.put("real_repayment", arr[2]);
			map.put("overdue_amount", arr[3]); //当 前 逾期总额 
			map.put("term_status","overdue");
			map.put("real_repayment_date",""); //实际还款时间
			map.put("overdue_status","D"+old_days);
			map.put("status_confirm_at",status_confirm_at);
			map.put("loan_status", "2");
			map.put("period_list", arr[4]);	
			val_Text.set(BHZXZDUtils.processZhudaiToString(map));
			context.write(key_null, val_Text);
		return Double.valueOf(arr[1]);		
	}
	/**
	 * 处理垫付结清、提前结清场景、债转场景
	 * @param context
	 * @param list_maps
	 * @param min_date
	 * @param act_payoff_time
	 * @param act_term_no
	 * @throws IOException
	 * @throws InterruptedException
	 */
	private static void process_advanceoff(Context context,List<Map<String,String>> list_maps,Map<String,String> map,String min_date) throws IOException, InterruptedException{
		String loan_payoff_time=map.get("loan_payoff_time");
		double act_amt=0;
		int old_days=0;
		StringBuilder sb = new StringBuilder(""); 
		for(Map<String,String> m:list_maps){
			if(!m.get("is_true").equals("true")){
				act_amt=act_amt+Double.parseDouble(m.get("planned_payment"))-Double.parseDouble(m.get("deduction_amount"));
				m.put("is_true", "true"); 
				sb.append(m.get("term_no")).append(",");
				
			}
		}
		    if(act_amt<=0){
		    	return;
		    }
		    if(min_date.equals("")){
		    	 old_days=0;
		    }else{
		    	 old_days=DateUtil.date_diff(BHZXZDUtils.time_to_date(loan_payoff_time), min_date);
		    }
		   
			//根据还款时间，判定本次还款进件所在期数
			map.put("target_repayment", String.valueOf(act_amt));
			map.put("remaining_amount","0");
			map.put("real_repayment", String.valueOf(act_amt));
			map.put("overdue_amount", "0"); //当 前 逾期总额 
			if(map.get("loan_status2").equals("ZZ")){
				map.put("term_status",old_days<=30?"thirdPartyPayIn30":"compensation");	
				map.put("loan_status", "5");
			}else{
				map.put("loan_status", "3");
				map.put("term_status","normal");
			}
			
			map.put("real_repayment_date",loan_payoff_time); //实际还款时间
			map.put("overdue_status","");
			map.put("status_confirm_at",loan_payoff_time);
			map.put("remaining_amount", "0"); //剩余本金 
			
			map.put("period_list", sb.length()<=0?"":sb.substring(0, sb.length()-1));	
			val_Text.set(BHZXZDUtils.processZhudaiToString(map));
			context.write(key_null, val_Text);
			   
	} 
	/**
	 * 资产处置、债转场景
	 * @param context
	 * @param list_maps
	 * @param min_date
	 * @param act_payoff_time
	 * @param act_term_no
	 * @throws IOException
	 * @throws InterruptedException
	 */
	private static void process_chuzhi(Context context,List<Map<String,String>> list_maps,Map<String,String> map) throws IOException, InterruptedException{
		String loan_payoff_time=map.get("loan_payoff_time");
		double remain_amt=0;
		int old_days=0;
		StringBuilder sb = new StringBuilder("");
		double overdue_amount=0;
		double loan_due_amt=0;
		String date_k;
		String dt="2019-11-01";
		int term_no=Integer.parseInt(map.get("term_no"));
		String min_due_date="";
		for(Map<String,String> m:list_maps){
			if(!m.get("is_true").equals("true")){
				remain_amt=remain_amt+Double.parseDouble(m.get("planned_payment"))-Double.parseDouble(m.get("deduction_amount"));
				
				date_k=DateUtil.formateDateStr(DateUtil.addDay(DateUtil.formateToDate(map.get("target_repayment_date"),"yyyy-MM-dd"), K+1),"yyyy-MM-dd");
				overdue_amount=overdue_amount+date_k.compareTo(dt)>=0?Double.valueOf(map.get("planned_payment")):0;
				if(min_due_date.equals("") || m.get("target_repayment_date").compareTo(min_due_date)<=0){
					min_due_date=m.get("target_repayment_date");
				}
				if(Integer.parseInt(m.get("term_no"))<=term_no ){ 
					loan_due_amt=loan_due_amt+Double.parseDouble(m.get("planned_payment"))-Double.parseDouble(m.get("deduction_amount"));
				}
				m.put("is_true", "true");
				sb.append(m.get("term_no")).append(",");
				
			}
		}
		    if(remain_amt<=0){
		    	return;
		    }
		    if(min_due_date.equals("")){
		    	 old_days=0;
		    }else{
		    	 old_days=DateUtil.date_diff(BHZXZDUtils.time_to_date(loan_payoff_time), min_due_date);
		    }
		   
			//根据还款时间，判定本次还款进件所在期数
			map.put("target_repayment", String.valueOf(loan_due_amt));
			map.put("remaining_amount",String.valueOf(remain_amt));
			map.put("real_repayment","0");
			map.put("overdue_amount", String.valueOf(overdue_amount)); //当 前 逾期总额 
			map.put("term_status","overdue");	
			map.put("loan_status", "5");
			
			map.put("real_repayment_date",""); //实际还款时间
			map.put("overdue_status",old_days>K?"D"+old_days:"");
			map.put("status_confirm_at",loan_payoff_time);
			
			map.put("period_list", sb.length()<=0?"":sb.substring(0, sb.length()-1));	
			val_Text.set(BHZXZDUtils.processZhudaiToString(map));
			context.write(key_null, val_Text);
			   
	} 

	//计算当期剩余应还款金额、借款剩余余额、本次实际还款金额
		private static String[] getLoan_due_amt(List<Map<String,String>> list_maps,int term_no,int act_term_no,String act_payoff_date){
				double loan_due_amt=0;
				String payoff_date="";
				double remain_amt=0;
				String[] arr=new String[5];
				double act_amount=0;
				double overdue_amount=0;
				StringBuilder sb = new StringBuilder("");
				for(Map<String,String> m :list_maps){
					payoff_date=BHZXZDUtils.time_to_date(m.get("payoff_time"));
					if(Integer.parseInt(m.get("term_no"))<=term_no && !m.get("is_true").equals("true")){ 
						loan_due_amt=loan_due_amt+Double.parseDouble(m.get("planned_payment"))-Double.parseDouble(m.get("deduction_amount"));
					}
					if(payoff_date.equals(act_payoff_date) && Integer.parseInt(m.get("term_no"))<=act_term_no && !m.get("is_true").equals("true")){ 
						act_amount=act_amount+Double.parseDouble(m.get("planned_payment"))-Double.parseDouble(m.get("deduction_amount"));
						m.put("is_true", "true");
						sb.append(m.get("term_no")).append(",");
					}
					if(!m.get("is_true").equals("true")){
						remain_amt=remain_amt+Double.parseDouble(m.get("planned_principal"));
					}
					if(Integer.parseInt(m.get("term_no"))<=term_no && !m.get("is_true").equals("true")){
						overdue_amount=overdue_amount+Double.parseDouble(m.get("planned_payment"));;
						
					}
					
	             }
				arr[0]=String.valueOf(loan_due_amt);
				arr[1]=String.valueOf(remain_amt);
				arr[2]=String.valueOf(act_amount);
				arr[3]=String.valueOf(overdue_amount);
				arr[4]=sb.length()<=0?"":sb.substring(0,sb.length()-1); 
				return arr;
			}
		private static double getLoan_remain_amt(List<Map<String,String>> list_maps){
 
			double remain_amt=0;
			 
			for(Map<String,String> m :list_maps){
				 
				if(!m.get("is_true").equals("true")){
					remain_amt=remain_amt+Double.parseDouble(m.get("planned_principal"));
				}
				 
				
             }
			 
			return remain_amt;
		}
	 
}
